﻿/*
* jQuery UI Droppable 1.8.10
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Droppables
*
* Depends:
*	jquery.ui.core.js
*	jquery.ui.widget.js
*	jquery.ui.mouse.js
*	jquery.ui.draggable.js
*/
(function ($, undefined) {

	$.widget("ui.droppable", {
		widgetEventPrefix: "drop",
		options: {
			accept: '*',
			activeClass: false,
			addClasses: true,
			greedy: false,
			hoverClass: false,
			scope: 'default',
			tolerance: 'intersect'
		},
		_create: function () {

			var o = this.options, accept = o.accept;
			this.isover = 0; this.isout = 1;

			this.accept = $.isFunction(accept) ? accept : function (d) {
				return d.is(accept);
			};

			//Store the droppable's proportions
			this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };

			// Add the reference and positions to the manager
			$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
			$.ui.ddmanager.droppables[o.scope].push(this);

			(o.addClasses && this.element.addClass("ui-droppable"));

		},

		destroy: function () {
			var drop = $.ui.ddmanager.droppables[this.options.scope];
			for (var i = 0; i < drop.length; i++)
				if (drop[i] == this)
					drop.splice(i, 1);

			this.element
			.removeClass("ui-droppable ui-droppable-disabled")
			.removeData("droppable")
			.unbind(".droppable");

			return this;
		},

		_setOption: function (key, value) {

			if (key == 'accept') {
				this.accept = $.isFunction(value) ? value : function (d) {
					return d.is(value);
				};
			}
			$.Widget.prototype._setOption.apply(this, arguments);
		},

		_activate: function (event) {
			var draggable = $.ui.ddmanager.current;
			if (this.options.activeClass) this.element.addClass(this.options.activeClass);
			(draggable && this._trigger('activate', event, this.ui(draggable)));
		},

		_deactivate: function (event) {
			var draggable = $.ui.ddmanager.current;
			if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
			(draggable && this._trigger('deactivate', event, this.ui(draggable)));
		},

		_over: function (event) {

			var draggable = $.ui.ddmanager.current;
			if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

			if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
				if (this.options.hoverClass) this.element.addClass(this.options.hoverClass);
				this._trigger('over', event, this.ui(draggable));
			}

		},

		_out: function (event) {

			var draggable = $.ui.ddmanager.current;
			if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

			if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
				if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
				this._trigger('out', event, this.ui(draggable));
			}

		},

		_drop: function (event, custom) {

			var draggable = custom || $.ui.ddmanager.current;
			if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element

			var childrenIntersection = false;
			this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function () {
				var inst = $.data(this, 'droppable');
				if (
				inst.options.greedy
				&& !inst.options.disabled
				&& inst.options.scope == draggable.options.scope
				&& inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
				&& $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
			) { childrenIntersection = true; return false; }
			});
			if (childrenIntersection) return false;

			if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
				if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
				if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
				this._trigger('drop', event, this.ui(draggable));
				return this.element;
			}

			return false;

		},

		ui: function (c) {
			return {
				draggable: (c.currentItem || c.element),
				helper: c.helper,
				position: c.position,
				offset: c.positionAbs
			};
		}

	});

	$.extend($.ui.droppable, {
		version: "1.8.10"
	});

	$.ui.intersect = function (draggable, droppable, toleranceMode) {

		if (!droppable.offset) return false;

		var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
		y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
		var l = droppable.offset.left, r = l + droppable.proportions.width,
		t = droppable.offset.top, b = t + droppable.proportions.height;

		switch (toleranceMode) {
			case 'fit':
				return (l <= x1 && x2 <= r
				&& t <= y1 && y2 <= b);
				break;
			case 'intersect':
				return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
				&& x2 - (draggable.helperProportions.width / 2) < r // Left Half
				&& t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
				&& y2 - (draggable.helperProportions.height / 2) < b); // Top Half
				break;
			case 'pointer':
				var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
				draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
				isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
				return isOver;
				break;
			case 'touch':
				return (
					(y1 >= t && y1 <= b) || // Top edge touching
					(y2 >= t && y2 <= b) || // Bottom edge touching
					(y1 < t && y2 > b)		// Surrounded vertically
				) && (
					(x1 >= l && x1 <= r) || // Left edge touching
					(x2 >= l && x2 <= r) || // Right edge touching
					(x1 < l && x2 > r)		// Surrounded horizontally
				);
				break;
			default:
				return false;
				break;
		}

	};

	/*
	This manager tracks offsets of draggables and droppables
	*/
	$.ui.ddmanager = {
		current: null,
		droppables: { 'default': [] },
		prepareOffsets: function (t, event) {

			var m = $.ui.ddmanager.droppables[t.options.scope] || [];
			var type = event ? event.type : null; // workaround for #2317
			var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();

			droppablesLoop: for (var i = 0; i < m.length; i++) {

				if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) continue; //No disabled and non-accepted
				for (var j = 0; j < list.length; j++) { if (list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
				m[i].visible = m[i].element.css("display") != "none"; if (!m[i].visible) continue; 									//If the element is not visible, continue

				m[i].offset = m[i].element.offset();
				m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };

				if (type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables

			}

		},
		drop: function (draggable, event) {

			var dropped = false;
			$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function () {

				if (!this.options) return;
				if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
					dropped = dropped || this._drop.call(this, event);

				if (!this.options.disabled && this.visible && this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
					this.isout = 1; this.isover = 0;
					this._deactivate.call(this, event);
				}

			});
			return dropped;

		},
		drag: function (draggable, event) {

			//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
			if (draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);

			//Run through all droppables and check their positions based on specific tolerance options
			$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function () {

				if (this.options.disabled || this.greedyChild || !this.visible) return;
				var intersects = $.ui.intersect(draggable, this, this.options.tolerance);

				var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
				if (!c) return;

				var parentInstance;
				if (this.options.greedy) {
					var parent = this.element.parents(':data(droppable):eq(0)');
					if (parent.length) {
						parentInstance = $.data(parent[0], 'droppable');
						parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
					}
				}

				// we just moved into a greedy child
				if (parentInstance && c == 'isover') {
					parentInstance['isover'] = 0;
					parentInstance['isout'] = 1;
					parentInstance._out.call(parentInstance, event);
				}

				this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
				this[c == "isover" ? "_over" : "_out"].call(this, event);

				// we just moved out of a greedy child
				if (parentInstance && c == 'isout') {
					parentInstance['isout'] = 0;
					parentInstance['isover'] = 1;
					parentInstance._over.call(parentInstance, event);
				}
			});

		}
	};

})(jQuery);

